package tr.gov.tubitak.uekae.esya.api.cades.example.sign;

import junit.framework.TestCase;
import tr.gov.tubitak.uekae.esya.api.asn.x509.ECertificate;
import tr.gov.tubitak.uekae.esya.api.cades.example.testconstans.TestConstants;
import tr.gov.tubitak.uekae.esya.api.cades.example.validation.ValidationUtil;
import tr.gov.tubitak.uekae.esya.api.cmssignature.SignableByteArray;
import tr.gov.tubitak.uekae.esya.api.cmssignature.attribute.EParameters;
import tr.gov.tubitak.uekae.esya.api.cmssignature.signature.BaseSignedData;
import tr.gov.tubitak.uekae.esya.api.cmssignature.signature.ESignatureType;
import tr.gov.tubitak.uekae.esya.api.cmssignature.signature.Signer;
import tr.gov.tubitak.uekae.esya.api.cmssignature.validation.SignedDataValidationResult;
import tr.gov.tubitak.uekae.esya.api.cmssignature.validation.SignedData_Status;
import tr.gov.tubitak.uekae.esya.api.common.crypto.BaseSigner;
import tr.gov.tubitak.uekae.esya.api.smartcard.example.SmartCardManager;
import tr.gov.tubitak.uekae.esya.api.smartcard.pkcs11.SmartCardException;
import tr.gov.tubitak.uekae.esya.asn.util.AsnIO;

import java.util.HashMap;
import java.util.List;

/**
 * Creates serial signature structures
 * @author orcun.ertugrul
 *
 */

public class SerialSign extends TestCase
{
	public final static int SIGNATURE_COUNT = 5;
	
	/**
	 * Creates a signature structure that has one different signer; and validates the structure.
	 * @throws Exception
	 */
	public void testSignInLoop() throws Exception
	{
		SmartCardManager scm = SmartCardManager.getInstance();
		
		ECertificate cert = scm.getSignatureCertificate(TestConstants.getCheckQCStatement(), !TestConstants.getCheckQCStatement());
		BaseSigner signer = scm.getSigner(TestConstants.getPIN(), cert);
		
		byte [] lastSign = singInLoop(cert,signer);
		
		scm.logout();
		
		AsnIO.dosyayaz(lastSign, TestConstants.getDirectory() + "testdata/counterSignatures.p7s");
		
		SignedDataValidationResult sdvr = ValidationUtil.validate(lastSign, null);
		
		assertEquals(SignedData_Status.ALL_VALID, sdvr.getSDStatus());


	}
	
	/**
	 * Creates a signature structure that has two different signers; and validates the structure.
	 * @throws Exception
	 */
	public void testSignInLoopWith2Signer() throws Exception
	{
		boolean checkQCStatement = TestConstants.getCheckQCStatement();
		
		System.out.println("Select card - 1");
		
		SmartCardManager.reset();
		
		SmartCardManager scm1 = SmartCardManager.getInstance();
		
		ECertificate cert1 = scm1.getSignatureCertificate(checkQCStatement, !checkQCStatement);
		BaseSigner signer1 = scm1.getSigner(TestConstants.getPIN(), cert1);
		
		SmartCardManager.reset();
		
		
		System.out.println("Select card - 2");
		
		SmartCardManager scm2 = SmartCardManager.getInstance();
		
		ECertificate cert2 = scm2.getSignatureCertificate(checkQCStatement, !checkQCStatement);
		BaseSigner signer2 = scm2.getSigner(TestConstants.getPIN(), cert2);
		
		SmartCardManager.reset();
		
		byte [] lastSign = singInLoopWith2Signer(cert1, signer1, cert2, signer2);
		
		try
		{
			scm1.logout();
			scm2.logout();
		}
		catch(SmartCardException sce)
		{
			sce.printStackTrace();
		}
		
		AsnIO.dosyayaz(lastSign, TestConstants.getDirectory() + "testdata/counterSignatures2.p7s");
		
		SignedDataValidationResult sdvr = ValidationUtil.validate(lastSign, null);
		
		assertEquals(SignedData_Status.ALL_VALID, sdvr.getSDStatus());

	}
	
	/***
	 * Creates signature structure that has one counter signature in every level. 
	 * @param cert
	 * @param signer
	 * @return
	 */
	public static byte [] singInLoop(ECertificate cert, BaseSigner signer) 
	{
		try
		{
			HashMap<String, Object> params = new HashMap<String, Object>();
			
			params.put(EParameters.P_CERT_VALIDATION_POLICY, TestConstants.getPolicy());
			params.put(EParameters.P_VALIDATE_CERTIFICATE_BEFORE_SIGNING, TestConstants.validateCertificate());
			
			byte [] content = "test".getBytes();
			byte [] sign = null;
			
			for(int i=0 ; i < SIGNATURE_COUNT; i++)
			{
				BaseSignedData bs;
				List<Signer> signerList = null;
				
				if(sign == null)
				{
					// there is no signature, add content
					bs = new BaseSignedData();
					bs.addContent(new SignableByteArray(content));
				}
				else
				{
					// there are signatures, get signer list.
					bs = new BaseSignedData(sign);
					signerList =  bs.getSignerList();
				}
			
				
				if(signerList!=null && signerList.size() > 0)
				{
					Signer lastSigner = signerList.get(signerList.size() - 1);
					while(lastSigner.getCounterSigners().size() > 0)
					{
						lastSigner = lastSigner.getCounterSigners().get(lastSigner.getCounterSigners().size()-1);
					}
					lastSigner.addCounterSigner(ESignatureType.TYPE_BES, cert, signer , null, params);
				}
				else
				{ 
					//add first signature.
					bs.addSigner(ESignatureType.TYPE_BES, cert, signer , null, params);
				}
				
				sign = bs.getEncoded();
			}
			
			return sign;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		
	}
	
	/**
	 * Creates signature structure that has two counter signatures in every level. 
	 * @param cert1
	 * @param signer1
	 * @param cert2
	 * @param signer2
	 * @return
	 */
	public static byte [] singInLoopWith2Signer(ECertificate cert1, BaseSigner signer1, ECertificate cert2, BaseSigner signer2) 
	{
		try
		{
			HashMap<String, Object> params = new HashMap<String, Object>();
			
			params.put(EParameters.P_CERT_VALIDATION_POLICY, TestConstants.getPolicy());
			
			byte [] content = "test".getBytes();
			byte [] signature = null;
			
			for(int i=0 ; i < SIGNATURE_COUNT; i++)
			{
				BaseSignedData bs;
				List<Signer> signerList = null;
				
				if(signature == null)
				{
					// there is no signature, add content
					bs = new BaseSignedData();
					bs.addContent(new SignableByteArray(content));
				}
				else
				{
					// there are signatures, get signer list.
					bs = new BaseSignedData(signature);
					signerList =  bs.getSignerList();
				}
				
				if(signerList!=null && signerList.size() > 0)
				{
					Signer lastSigner = signerList.get(signerList.size() - 1);
					while(lastSigner.getCounterSigners().size() > 0)
					{
						lastSigner = lastSigner.getCounterSigners().get(lastSigner.getCounterSigners().size()-1);
					}
					lastSigner.addCounterSigner(ESignatureType.TYPE_BES, cert1, signer1 , null, params);
					lastSigner.addCounterSigner(ESignatureType.TYPE_BES, cert2, signer2 , null, params);
				}
				else
				{
					//add first level two signatures.
					bs.addSigner(ESignatureType.TYPE_BES, cert1, signer1, null, params);
					bs.addSigner(ESignatureType.TYPE_BES, cert2, signer2, null, params);
				}
				
				signature = bs.getEncoded();
			}
			
			return signature;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		
	}
	



	

	
}
